<!DOCTYPE html>
<html>
<body>
<canvas id="canvas" width="3" height="2"></canvas>
<script src="../../resources/js-test.js"></script>
<script>
jsTestIsAsync = true;
var worker = new Worker('./resources/canvas-ImageBitmap-structured-clone.js');

description("Tests that ImageBitmap supports structured clone and that the pixel data survives the trip between main <--> worker");

function shouldNotBeCalled(e) {
  testFailed("promise rejected." + e);
  finishJSTest();
}

function compareImageData(data1, data2)
{
  if (data1.length != data2.length) {
    testFailed("The two image have different dimensions");
    return;
  }
  for (var i = 0; i < data1.length; i++) {
    if ((i % 4 != 3 && Math.abs(data1[i] - data2[i]) > 5) ||
         (i % 4 == 3 && data1[i] != data2[i])) {
      testFailed("The ImageBitmap pixel data did not survive the round trip");
      return;
    }
  }
  testPassed("The ImageBitmap pixel data survives the round trip");
}

function checkImageBitmap1() {
  shouldBe("bitmapWidth", "imageWidth1");
  shouldBe("bitmapHeight", "imageHeight1");

  // newImage is not necessary the same as imageData because of
  // multiplying and dividing by alpha during the round trip, but
  // they should be close.
  // The alpha channel should be exactly the same.
  compareImageData(newImage.data, imageData1);
}

function checkImageBitmap2() {
  shouldBe("bitmapWidth", "imageWidth2");
  shouldBe("bitmapHeight", "imageHeight2");

  compareImageData(newImage.data, imageData2);
}

function postToWorker(message, transferable) {
  return new Promise((resolve, reject) => {
    function onMessage(e) {
      resolve(e.data);
      worker.removeEventListener("message", onMessage);
    }
    worker.postMessage(message, transferable);
    worker.addEventListener("message", onMessage);
  });
}

function getNewImageDataFromImageBitmap(newImageBitmap)
{
  bitmapWidth = newImageBitmap.width;
  bitmapHeight = newImageBitmap.height;
  context.clearRect(0, 0, imageWidth1, imageHeight1);
  context.drawImage(newImageBitmap, 0, 0, bitmapWidth, bitmapHeight);
  newImage = context.getImageData(0, 0, bitmapWidth, bitmapHeight);
}

var imageWidth1 = 3;
var imageHeight1 = 2;
var imageWidth2 = 1;
var imageHeight2 = 1;
var bitmapWidth;
var bitmapHeight;
var imageBitmap1;
var imageBitmap2;
var newImage;
var imageData1;
var imageData2;
var image1 = new ImageData(new Uint8ClampedArray(
            [255, 0, 0, 255,
            0, 255, 0, 255,
            255, 255, 255, 127,
            0, 0, 0, 64,
            12, 34, 56, 64,
            12, 34, 56, 127]),
            imageWidth1, imageHeight1);
var image2 = new ImageData(new Uint8ClampedArray([255, 128, 64, 127]), imageWidth2, imageHeight2);
var context = document.getElementById("canvas").getContext("2d");

var p1 = createImageBitmap(image1).then(function(image) {imageBitmap1 = image});
var p2 = createImageBitmap(image2, {imageOrientation: "none", premultiplyAlpha: "none"}).then(function(image) {imageBitmap2 = image});
Promise.all([p1, p2]).then(function() {
  getNewImageDataFromImageBitmap(imageBitmap1);
  imageData1 = newImage.data;
  getNewImageDataFromImageBitmap(imageBitmap2);
  imageData2 = newImage.data;

  bitmapWidth = imageBitmap1.width;
  bitmapHeight = imageBitmap1.height;
  shouldBe("bitmapWidth", "imageWidth1");
  shouldBe("bitmapHeight", "imageHeight1");

  var replyPromise = postToWorker(imageBitmap1);

  // Structured cloning should not neuter the source ImageBitmap
  bitmapWidth = imageBitmap1.width;
  bitmapHeight = imageBitmap1.height;
  shouldBe("bitmapWidth", "imageWidth1");
  shouldBe("bitmapHeight", "imageHeight1");

  return replyPromise.then(reply => {
    getNewImageDataFromImageBitmap(reply);
    checkImageBitmap1();
  });
}).then(function() {
  var replyPromise = postToWorker(imageBitmap1, [imageBitmap1]);

  // Transfer the ImageBitmap should neuter it
  bitmapWidth = imageBitmap1.width;
  bitmapHeight = imageBitmap1.height;
  shouldBe("bitmapWidth", "0");
  shouldBe("bitmapHeight", "0");

  return replyPromise.then(reply => {
    getNewImageDataFromImageBitmap(reply);
    checkImageBitmap1();
  });
}).then(function() {
  var replyPromise = postToWorker(imageBitmap2);

  // Structured cloning should not neuter the source ImageBitmap
  bitmapWidth = imageBitmap2.width;
  bitmapHeight = imageBitmap2.height;
  shouldBe("bitmapWidth", "imageWidth2");
  shouldBe("bitmapHeight", "imageHeight2");

  return replyPromise.then(reply => {
    getNewImageDataFromImageBitmap(reply);
    checkImageBitmap2();
  });
}).then(finishJSTest, shouldNotBeCalled);
</script>
</body>
</html>
